package com.apes.fn.scm.retailOrder.model;

import com.alibaba.fastjson.annotation.JSONField;
import com.apes.crm.business.model.InsuranceCompany;
import com.apes.fn.crm.customerExpand.FnCustomerExpand;
import com.apes.framework.api.SpringManager;
import com.apes.framework.jpa.DefaultPersistListener;
import com.apes.framework.jpa.Model;
import com.apes.framework.jpa.comment.Comment;
import com.apes.framework.jpa.generator.ApesGenerator;
import com.apes.framework.plugin.soe.annotations.State;
import com.apes.framework.plugin.soe.annotations.States;
import com.apes.framework.plugin.soe.metadata.BusinessAttributeValue;
import com.apes.framework.util.*;
import com.apes.scm.masterdata.enumeration.model.Enumeration;
import com.apes.scm.masterdata.frame.model.Channel;
import com.apes.scm.masterdata.frame.model.Dept;
import com.apes.scm.masterdata.party.model.PartyRole;
import com.apes.scm.masterdata.party.service.PartyRoleService;
import lombok.Getter;
import lombok.Setter;
import org.hibernate.annotations.DynamicInsert;
import org.hibernate.annotations.DynamicUpdate;
import org.hibernate.annotations.SelectBeforeUpdate;
import org.springframework.util.StringUtils;

import javax.persistence.*;
import java.util.*;

/**
 * 功能：零售单
 *
 * @author HuJianlin
 * @create 2018-10-31 15:36
 */
@Getter
@Setter
@SelectBeforeUpdate
@DynamicInsert
@DynamicUpdate
@Entity
@EntityListeners(DefaultPersistListener.class)
@Table(name = RetailOrder.CONST_TABLE_NAME, indexes = {@Index(columnList = "creator_id"), @Index(columnList = "dept_id,state,orderType,is_return_all")})
public class RetailOrder extends Model {
    public static final String CONST_TABLE_NAME = "retail_order";

    @Id
    @Column(name = "id")
    @Comment("零售单号")
    @ApesGenerator(code = CONST_TABLE_NAME, name = "零售单", prefix = "LS%(company)%(yy)%(month)", padding = 5, useDateRange = true)
    private String id;

    @Comment("公司")
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "company_id", referencedColumnName = "id", nullable = false)
    private PartyRole company;  //

    @Comment("部门")
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "dept_id", referencedColumnName = "id", nullable = false)
    private Dept dept;

    @Comment("业务员")
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "clerk_id", referencedColumnName = "id")
    private PartyRole clerk;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "insurance_company_id", referencedColumnName = "id")
    @Comment("保险公司")
    private InsuranceCompany insuranceCompany; //保险公司（定损业务中对应的保险公司;收票方）

    @Column(name = "insurance_Report_Order", length = 64)
    @Comment("保险公司报案号")
    private String insuranceReportNumber;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "service_dept_id", referencedColumnName = "id")
    @Comment("服务门店")
    private Dept serviceDept; //服务门店（实际做维修的门店;）

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "get_Car_Dept", referencedColumnName = "id")
    @Comment("接车门店")
    private Dept getCarDept;

    @Comment("收款方")
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "payment_id", referencedColumnName = "id")
    private PartyRole payment;  // 直赔—销售公司;非直赔—接车门店

    @Comment("开票方")
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "make_invoice_id", referencedColumnName = "id")
    private PartyRole makeInvoice;

    @Comment("会员扩展信息")
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "customer_expand_id", referencedColumnName = "id")
    private FnCustomerExpand customerExpand;

    @Comment("单位客户标记")
    @Column(name = "unit_customer", columnDefinition = ApesConst.FIELD_BOOLEAN_TRUE)
    private boolean unitCustomer = false;

    @Transient
    private Map customerCar;

    public Map getCustomerCar() {
        if (customerExpand == null || customerExpand.getCarLicense() == null) return null;
        return MapUtil.mapper(
                "carLicense", customerExpand.getCarLicense(),
                "vendorCode", customerExpand.getVendorCode(),
                "customer", this.getCustomer()
        );
    }

    @Transient
    private Map customer;

    @Transient
    private PartyRole customer_real;  //客户

    public Map getCustomer() {
        if (customerExpand == null || customerExpand.getMobile() == null) return null;
        return MapUtil.mapper(
                "realname", customerExpand.getRealname(),
                "vendorCode", customerExpand.getVendorCode(),
                "mobile", customerExpand.getMobile()
        );
    }

    /*** 字段说明 ***/
    // 服务："server"  年卡："yearcard" 年卡退款："yearCardReturn"  普通单:"generalOrder"
    // 储值单:"storedValue"  零售退货单："retailReturn"   定损单："DS0" 或者 "lossQuotation"
    // 兑换券置换："replacement"   兑换券购买："buyVoucher"  年审订单："annualAudit"  收款方式调整: "paymentUpdate"
    // e保养+ 退款 ePlus_Return   定损收款方式调整："lossPaymentUpdate"    车险退保："vehicleInsuranceSurrender"
    // 检测报告  detectReport
    @Comment("单据类型")
    @Column(name = "orderType", length = 30)
    private String orderType;  // 订单类型

    @Comment("年卡类别")
    @Column(name = "year_card_type", length = 4)
    private String yearCardType; // 年卡类别: ("01", "美容年卡") ("02", "美容保养年卡")

    @Comment("源单据")
    @Column(name = "origin", length = 30)
    private String origin;  // APP 订单号

    @Column(name = "source", length = 30)
    @Comment("来源单据")
    private String source;

    @Column(name = "source_business_type", length = 32)
    @Comment("来源单据类型")
    private String sourceBusinessType;     // 定损报价单（DS0 或者 LossQuotation）

    public String getSourceBusinessType() {
        if (StringUtils.isEmpty(sourceBusinessType)) {
            return this.getOrderType();
        }
        return this.sourceBusinessType;
    }

    @Comment("订单备注")
    @Column(name = "remark", length = 120)
    private String remark;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "approve_uid", referencedColumnName = "id")
    @Comment("审核人")
    private PartyRole approveUID; //审核

    @Comment("审批日期")
    @Column(name = "date_approve")
    private Date dateApprove;

    @Comment("完成日期")
    @Column(name = "date_done")
    private Date dateDone;

    @Comment("计划日期")
    @Column(name = "date_planned")
    private Date datePlanned;

    @Comment("取消日期")
    @Column(name = "date_cancel")
    private Date dateCancel;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "delete_uid", referencedColumnName = "id")
    @Comment("删除人")
    private PartyRole deleteUID; //删除

    @Column(name = "delete_date")
    @Comment("删除日期")
    private Date deleteDate; //删除日期

    @States(name = "订单状态", values = {
            @State(id = "sent", name = "创建"),
            @State(id = "confirmed", name = "审核"),
            @State(id = "done", name = "交货完成"),
            @State(id = "vouched", name = "凭证完成"),
            @State(id = "cancel", name = "已取消")})
    @Column(name = "state", length = 10, nullable = false)
    private String state = "sent";

    @Comment("送货状态")
    @Column(name = "is_shipped", nullable = false)
    private boolean shipped = false;

    @Comment("开票状态")
    @Column(name = "invoice_status", nullable = false, length = 10)
    private String invoiceStatus = "no"; //账单状态: ("no", "未开票") (默认值), ("to_invoice", "开票中"), ("invoiced", "已开票")

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "move_type", referencedColumnName = "id")
    private Enumeration moveType; //交货方式：("direct", "部分交货"), ("one", "一次性交货");

    @Column(name = "discount_amount", nullable = false, columnDefinition = ApesConst.FIELD_MONEY_16_4_0)
    @Comment("折扣金额")
    private double discountAmount = 0;

    @Comment("税金")
    @Column(name = "amt_tax", nullable = false, columnDefinition = ApesConst.FIELD_MONEY_16_4_0)
    private double amtTax = 0;

    @Comment("不含税金额")
    @Column(name = "amt_untaxed", nullable = false, columnDefinition = ApesConst.FIELD_MONEY_16_4_0)
    private double amtUntaxed = 0;

    @Comment("总计")
    @Column(name = "amt_total", nullable = false, columnDefinition = ApesConst.FIELD_MONEY_16_4_0)
    private double amtTotal = 0; //总计


    @Comment("实收金额")
    @Column(name = "actual_total", columnDefinition = ApesConst.FIELD_MONEY_16_4_0)
    private double actualAmount = 0;  //实收金额

    @Comment("已开票金额")
    @Column(name = "invoiced_amount", columnDefinition = ApesConst.FIELD_MONEY_16_4_0)
    private double invoicedAmount = 0;  //已开票金额

    @Transient
    private double unInvoicedAmount = 0;  //未开票金额

    public double getActualAmount() {
        return Arith.sub(amtTotal, discountAmount);
    }

    public double getUnInvoicedAmount() {
        if (LogicalUtil.in(orderType, "lossPaymentUpdate", "paymentUpdate") || saleItems == null) return 0;
        return Arith.sub(Arith.sub(amtTotal, discountAmount), saleItems.stream().map(RetailOrderItem::getInvoicedAmount).reduce(Arith::add).orElse(0.0));
    }

    @Transient
    private double otherReceivableAmount = 0;  //收款方式其它应收金额

    public double getOtherReceivableAmount() {
        if (this.paymentMethodSet == null) return 0;
        return paymentMethodSet.stream().filter(payment -> payment.getPaymentMethodType().getId().equals("09")).mapToDouble(RetailOrderPayMethod::getAmount).sum();
    }

    @Transient
    private double invoicingAmount = 0;  //可开票金额 actualAmount - otherReceivableAmount

    public double getInvoicingAmount() {
        return Arith.sub(actualAmount, otherReceivableAmount);
    }


    @Comment("套包提成")
    @Column(name = "package_commission", nullable = false, columnDefinition = ApesConst.FIELD_MONEY_16_4_0)
    private double packageCommission = 0; //套包提成

    @Comment("案件类型")
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "case_type", referencedColumnName = "id")
    private Enumeration caseType;

    @Comment("理赔类型")
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "claim_Type", referencedColumnName = "id")
    private BusinessAttributeValue claimType;   // ("A":"直赔", "B":"快赔", "C":"传统理赔")

    @Column(name = "help_Reported", columnDefinition = ApesConst.FIELD_BOOLEAN_FALSE)
    @Comment("代报案标识")
    private boolean helpReported = false;

    @Transient
    private boolean balanceUse;

    @Transient
    private double balanceConsumption = 0;

    @States(name = "退货类型", values = {
            @State(id = "A", name = "有原单退货"),
            @State(id = "B", name = "无原单退货")})
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "return_type", referencedColumnName = "id")
    private BusinessAttributeValue returnType;

    @Comment("是否全部退货")
    @Column(name = "is_return_all")
    private boolean returnAll = false;

    @Comment("是否平台引流")
    @Column(name = "is_platform_flow", nullable = false, columnDefinition = ApesConst.FIELD_BOOLEAN_FALSE)
    private boolean platformFlow = false;

    @Comment("渠道")
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "channel_id", referencedColumnName = "id")
    private Channel channel;  // 渠道

    @Column(name = "supplier_ref", length = 30)
    @Comment("第三方单号")
    private String supplierRef;     //来源为天猫的，需要传入这个字段

    @Column(name = "app_Number", length = 30)
    @Comment("APP订单号")
    private String appNumber;

    @Column(name = "sinopec_Number", length = 30)
    @Comment("中石化单号")
    private String sinopecNumber;     // 中石化单号，需要传入这个字段

    @JSONField(format = DateUtil.SHOW_DATE_FORMAT)
    @Temporal(TemporalType.DATE)
    @Column(name = "post_date")
    @Comment("记账日期")
    private Date postDate;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "insurance_discounts", referencedColumnName = "id")
    @Comment("车险优惠方案")
    private Enumeration insuranceDiscounts;

    @Comment("车险优惠方案金额")    // e 保养对账金额
    @Column(name = "insurance_Discounts_Amt", nullable = false, columnDefinition = ApesConst.FIELD_MONEY_16_4_0)
    private double insuranceDiscountsAmt = 0;

    @Comment("是否E保养类订单")
    @Column(name = "is_insurance_Discounts", nullable = false, columnDefinition = ApesConst.FIELD_BOOLEAN_FALSE)
    private boolean insuranceDiscountFlag = false;

    @Comment("分销客户")
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "sale_Customer", referencedColumnName = "id")
    private PartyRole saleCustomer;

    @Column(name = "calculate_flag", columnDefinition = ApesConst.FIELD_BOOLEAN_FALSE)
    @Comment("计费完成标记")
    private boolean calculateFlag = false;

    @Column(name = "app_calc_flag", columnDefinition = ApesConst.FIELD_BOOLEAN_FALSE)
    @Comment("app计算提成标记")
    private boolean appCalcFlag = false;

    @Transient
    private boolean productFinished;    // 用于场景流中判断是否能生成凭证

    @Transient
    private boolean collection = false; //代收款标识


    /**
     * 检查是否所有的商品已经发货，或者是提单冲红完成
     * 解决问题：由于正常的零售单还在发货中，被提单冲红掉了，正向的单据流程没有走完，逆向的单据找不到正向单据的流程
     *
     * @return boolean
     */
    public boolean getProductFinished() {
        if (LogicalUtil.in(orderType, "lossPaymentUpdate", "paymentUpdate") || saleItems == null) return true;
        boolean productFinished = false;
        long count = saleItems.stream()
                // 需要发货的商品就判断，销售数量 = 发货数量 + 提单冲红数量（因为存在部分冲红）
                .filter(saleItem -> (saleItem.getProductRule() == 0 && saleItem.getLocation() != null)
                        && saleItem.getProductUomQty() != saleItem.getQtyDeliver() + saleItem.getQtyReturned()).count();
        if (count == 0) productFinished = true;
        return productFinished;
    }

    @OneToMany(mappedBy = "order", cascade = CascadeType.ALL, orphanRemoval = true)
    private Set<RetailOrderItem> saleItems = new HashSet(); //订单行

    public Set<RetailOrderItem> getSaleItems() {
        if (saleItems == null) return new HashSet();
        double discountAmounts = 0;
        for (RetailOrderItem item : saleItems) {
            // 去除数量为 0 的行
            if (item.getProductUomQty() == 0) {
                saleItems.remove(item);
                continue;
            }
            item.setOrder(this);
            item.setCompany(this.dept.getCompany());
            discountAmounts += item.getDiscountAmount();
        }
        discountAmount = discountAmounts;
        return saleItems;
    }

    @OneToMany(mappedBy = "order", cascade = CascadeType.ALL, orphanRemoval = true)
    private Set<RetailOrderPayMethod> paymentMethodSet = new HashSet(); // 付款方式明细

    public Set<RetailOrderPayMethod> getPaymentMethodSet() {
        if (paymentMethodSet == null || paymentMethodSet.isEmpty()) return new HashSet<>();
        balanceConsumption = 0;

        for (RetailOrderPayMethod item : paymentMethodSet) {
            item.setOrder(this);
            //余额消费标记
            if (item.getPaymentMethodType().getId().equals("05") || item.getPaymentMethodType().getId().equals("12")) {
                balanceUse = true;
                balanceConsumption += item.getAmount();
            }
            if (!collection) {
                collection = item.getPaymentMethodType().isCollection();
            }
        }
        return paymentMethodSet;
    }

    public void setPaymentMethodSet(Set<RetailOrderPayMethod> paymentMethodSet) {
        this.paymentMethodSet = paymentMethodSet;
    }

    public void computeAmt() {
        // 防止计算重复，赋初值
        amtUntaxed = 0;
        amtTax = 0;
        for (RetailOrderItem item : saleItems) {
            // 由于兑换券置换时，控制修改
            if (item.getPriceUnit() == 0 && !"replacement".equals(orderType)) throw new RuntimeException("单价不能为零，请检查!");
            item.computeAmt();
            amtUntaxed += item.getPriceSubtotal();
            amtTax += item.getPriceTax();
        }
        amtTotal = amtUntaxed + amtTax;
        actualAmount = amtTotal - discountAmount;
    }

    /**
     * 判断明细金额是否与总金额一直
     *
     * @return
     */
    public boolean checksaleItemsAcountEqual() {
        double itemaccout = 0;
        for (RetailOrderItem item : saleItems) {
            // 去除数量为 0 的行
            if (item.getProductUomQty() == 0) {
                continue;
            }
            itemaccout = itemaccout + item.getPriceTotal();
        }

        if (Arith.compare(itemaccout, amtTotal, 0.01) != 0) {
            throw new RuntimeException("订单明细金额与总金额不一致！");
        }
        return false;
    }

    /**
     * 根据单据类型查找源单据
     *
     * @return orderTypeName
     */
    public String orderTypeName() {
        if (StringUtils.isEmpty(orderType)) return "";

        if ("yearcard".equals(orderType)) {
            return "年卡";
        } else if ("yearCardReturn".equals(orderType)) {
            return "年卡退回单";
        } else if ("generalOrder".equals(orderType)) {
            return "普通单";
        } else if ("storedValue".equals(orderType)) {
            return "储值单";
        } else if ("retailReturn".equals(orderType)) {
            return "零售退货";
        } else if ("DS0".equals(orderType)) {
            return "老定损报价";
        } else if ("replacement".equals(orderType)) {
            return "兑换券置换";
        } else if ("buyVoucher".equals(orderType)) {
            return "兑换券购买";
        } else if ("annualAudit".equals(orderType)) {
            return "年审订单";
        } else if ("paymentUpdate".equals(orderType)) {
            return "收款方式调整";
        } else if ("ePlus_Return".equals(orderType)) {
            return "e服务+";
        } else if ("lossPaymentUpdate".equals(orderType)) {
            return "定损收款方式调整";
        } else if ("noDirectPay".equals(orderType) || "LossQuotation".equals(orderType)) {
            return "定损报价";
        } else if ("directPay".equals(orderType)) {
            return "直赔";
        } else if ("server".equals(orderType)) {
            return "服务";
        } else if ("detectReport".equals(orderType)) {
            return "电池检测报告";
        } else {
            return "";
        }
    }

    /**
     * 判断支付金额与总金额是否一致
     *
     * @return
     */
    public boolean checkPaymentMethodSetMoneyEqual() {
        double paymentAccount = 0;
        for (RetailOrderPayMethod item : paymentMethodSet) {
            paymentAccount = paymentAccount + item.getAmount();
            if (item.getPaymentMethodType().getId().equals("09") && item.getCustomer() == null) {
                throw new RuntimeException("收款方式为其他应收，付款客户为空，请检查！");
            }
        }

        if (Math.abs(Arith.round(amtTotal - discountAmount - paymentAccount, 2)) > 0.001) {
            throw new RuntimeException("支付金额与总金额不一致！");
        }
        return false;
    }

    /**
     * 检查退货数量
     */
    public void checkQtyReturned() {
        long count = getSaleItems().stream().filter(retailOrderItem -> retailOrderItem.getQtyReturned() == retailOrderItem.getProductUomQty()).count();
        if (count == getSaleItems().size()) {
            setReturnAll(true);
        }
    }

    /**
     * 平台公司
     **/
    @Transient
    private PartyRole platformCompany;


    public PartyRole getPlatformCompany() {
        if (platformCompany != null) return platformCompany;
        String topic = "event:fn.contract.findFirstValidFnContractCompanyByPartnerId";
        String platformCompanyId = (String) EventUtil.sendSynEvent(this, topic, MapUtil.mapper("partnerId", getCompany().getId())).stream().findFirst().get();
        if (!StringUtils.isEmpty(platformCompanyId)) {
            platformCompany = (PartyRole) JpaUtil.getImplementation(SpringManager.getBean(PartyRoleService.class).findOne(platformCompanyId, "Company"));
            platformCompany = MapUtil.getO(MapUtil.mapped(platformCompany), PartyRole.class);
        }
        return platformCompany;
    }
}
